/**
 * @file https_client.cc
 * @brief 🔗 HTTPS客户端实现文件 - 实现与服务器的HTTP通信
 */

#include "https_client.h"
#include "esp_log.h"
#include "esp_crt_bundle.h"
#include "esp_random.h"
#include <cstring>
#include <sstream>
#include <iomanip>
#include "common/settings.h"
#include <algorithm>

static const char *TAG = "HttpsClient";

HttpsClient::HttpsClient(const std::string& base_url)
    : base_url_(base_url), client_(nullptr), connected_(false) {
}

HttpsClient::~HttpsClient() {
    if (client_ != nullptr) {
        esp_http_client_cleanup(client_);
        client_ = nullptr;
    }
}

void HttpsClient::setEventCallback(EventCallback callback) {
    event_callback_ = callback;
}

esp_err_t HttpsClient::http_event_handler(esp_http_client_event_t* event) {
    HttpsClient* http_client = static_cast<HttpsClient*>(event->user_data);
    EventData event_data;
    event_data.data = nullptr;
    event_data.data_len = 0;
    event_data.status_code = 0;
    char url_get[256];
    switch (event->event_id) {
        case HTTP_EVENT_ON_CONNECTED:
            ESP_LOGI(TAG, "🔗 HTTP已连接");
            http_client->connected_ = true;
            event_data.type = EventType::CONNECTED;
            esp_http_client_get_url(http_client->client_,url_get,256);
            event_data.url = url_get;
            break;

        case HTTP_EVENT_ON_FINISH:
            ESP_LOGI(TAG, "✅ HTTP请求完成");
            http_client->connected_ = false;
            event_data.type = EventType::DISCONNECTED;
            break;

        case HTTP_EVENT_ON_DATA:
            ESP_LOGD(TAG, "📥 收到HTTP数据，长度: %d 字节", event->data_len);
            event_data.data = (const uint8_t*)event->data;
            event_data.data_len = event->data_len;
            event_data.type = EventType::DATA_RECEIVED;
            break;

        case HTTP_EVENT_ON_HEADER:
            // 可以在这里处理响应头
            break;

        case HTTP_EVENT_DISCONNECTED:
            ESP_LOGI(TAG, "🔌 HTTP已断开");
            http_client->connected_ = false;
            event_data.type = EventType::DISCONNECTED;
            break;

        case HTTP_EVENT_ERROR:
            ESP_LOGE(TAG, "❌ HTTP错误");
            http_client->connected_ = false;
            event_data.type = EventType::ERROR;
            break;

        default:
            return ESP_OK;
    }

    if (http_client->event_callback_) {
        http_client->event_callback_(event_data);
    }

    return ESP_OK;
}

esp_err_t HttpsClient::get(const std::string& path, int timeout_ms) {
    if (client_ != nullptr) {
        ESP_LOGW(TAG, "HTTP客户端已存在");
        return ESP_FAIL;
    }

    std::string url = base_url_ + path;
    ESP_LOGI(TAG, "🌐 正在发送GET请求到: %s", url.c_str());

    const int max_retries = 3;
    const int retry_delay_ms = 3000;
    esp_err_t err = ESP_FAIL;

    for (int retry = 0; retry < max_retries; retry++) {
        esp_http_client_config_t config = {};
        config.url = url.c_str();
        config.event_handler = http_event_handler;
        config.user_data = this;
        config.timeout_ms = timeout_ms;
        config.crt_bundle_attach = esp_crt_bundle_attach;
        config.buffer_size = BUFFER_SIZE;
        config.buffer_size_tx = BUFFER_SIZE;
        config.keep_alive_enable = true; // 启用Keep-Alive连接
        
        client_ = esp_http_client_init(&config);
        if (client_ == nullptr) {
            ESP_LOGE(TAG, "❌ HTTP客户端初始化失败");
            return ESP_FAIL;
        }

        err = esp_http_client_perform(client_);
        if (err == ESP_OK) {
            break;
        }

        ESP_LOGW(TAG, "HTTP请求失败(尝试 %d/%d): %s", 
                retry + 1, max_retries, esp_err_to_name(err));
        
        esp_http_client_cleanup(client_);
        client_ = nullptr;

        if (retry < max_retries - 1) {
            vTaskDelay(pdMS_TO_TICKS(retry_delay_ms));
        }
    }

    if (err != ESP_OK) {
        ESP_LOGE(TAG, "HTTP请求最终失败: %s", esp_err_to_name(err));
        return err;
    }

    int status_code = esp_http_client_get_status_code(client_);
    ESP_LOGI(TAG, "HTTP状态码: %d", status_code);

    esp_http_client_cleanup(client_);
    client_ = nullptr;

    return ESP_OK;
}

esp_err_t HttpsClient::postAudioData(const std::string& path, const uint8_t* data, size_t len,
                                   int timeout_ms) {
    if (client_ != nullptr) {
        ESP_LOGW(TAG, "HTTP客户端已存在");
        return ESP_FAIL;
    }

    // 生成唯一边界字符串
    std::string boundary = "----WebKitFormBoundary" + std::to_string(esp_random());

    // 获取当前时间戳(毫秒)
    int64_t timestamp = esp_timer_get_time() / 1000;
    
    // 生成UUID (8-4-4-4-12格式)
    uint32_t uuid_parts[5];
    for (int i = 0; i < 5; i++) {
        uuid_parts[i] = esp_random();
    }
    
    std::stringstream uuid_ss;
    uuid_ss << std::hex << std::setfill('0');
    uuid_ss << std::setw(8) << uuid_parts[0] << "-"
            << std::setw(4) << (uuid_parts[1] & 0xFFFF) << "-"
            << std::setw(4) << (uuid_parts[2] & 0xFFFF) << "-"
            << std::setw(4) << (uuid_parts[3] & 0xFFFF) << "-"
            << std::setw(12) << (uuid_parts[4] & 0xFFFFFFF);
    std::string uuid = uuid_ss.str();
    
    // 构造seqId和messageId (uuid + 5个下划线 + 时间戳)
    std::string seq_id = uuid + "_____" + std::to_string(timestamp);
    
    
    Settings http_params("http_params",true);
    // 存储相关参数
    http_params.SetString("messageId", seq_id);
    // 获取相关参数
    std::string userID = http_params.GetString("user_id");
    if (userID.empty()) {
        userID = "c5own"; // 如果没有设置，则使用默认USER_ID
    }
    std::string wsID = http_params.GetString("ws_id");
    if (wsID.empty()) {
        wsID = "ws:" + std::to_string(esp_random() % 1000000); // 如果没有设置，则生成一个随机的wsID
    }
    std::string sessionID = http_params.GetString("session_id");
    if (sessionID.empty()) {
        sessionID = "3e3de9c95fd14860ad85a18058309f06"; // 如果没有设置，则使用默认SEEION_ID
    }

    ESP_LOGI(TAG, "🌐 正在发送音频数据到: %s", (base_url_ + path).c_str());
    ESP_LOGI(TAG, "音频数据长度: %zu 字节", len);
    ESP_LOGI(TAG, "时间戳: %lld, seqId: %s, userId: %s, wsId: %s sessionID: %s", 
            timestamp, seq_id.c_str(), userID.c_str(), wsID.c_str(), sessionID.c_str());

    // 构造form-data请求体
    std::string body;
    
    // 添加JSON元数据部分
    body += "--" + boundary + "\r\n";
    body += "Content-Disposition: form-data; name=\"requestData\"\r\n";
    body += "Content-Type: application/json\r\n\r\n";
    body += "{"
        "\"timestamp\":" + std::to_string(timestamp) + ","
        "\"seqId\":\"" + seq_id + "\","
        "\"messageId\":\"" + seq_id + "\","
        "\"sendUserId\":\"" + userID + "\","
        "\"data\":{"
            "\"content\":\"\""
        "},"
        "\"sessionId\":\"" + sessionID + "\","
        "\"userId\":\"" + userID + "\","
        "\"wsId\":\"" + wsID + "\""
    "}\r\n";

    // 添加音频数据部分
    body += "--" + boundary + "\r\n";
    body += "Content-Disposition: form-data; name=\"file\"; filename=\"record.pcm\"\r\n";
    body += "Content-Type: audio/L16; rate=16000; channels=1\r\n\r\n";

    // 计算总数据长度
    size_t total_len = body.length() + len + (boundary.length() + 6); // +6 for "--boundary--\r\n"

    // 初始化HTTP客户端
    std::string url = base_url_ + path;
    esp_http_client_config_t config = {};
    config.url = url.c_str();
    config.event_handler = http_event_handler;
    config.user_data = this;
    config.timeout_ms = timeout_ms;
    config.crt_bundle_attach = esp_crt_bundle_attach;
    config.buffer_size = BUFFER_SIZE;
    config.buffer_size_tx = BUFFER_SIZE;

    client_ = esp_http_client_init(&config);
    if (client_ == nullptr) {
        ESP_LOGE(TAG, "❌ HTTP客户端初始化失败");
        return ESP_FAIL;
    }

    // 设置POST方法和内容类型
    esp_http_client_set_method(client_, HTTP_METHOD_POST);
    std::string content_type = "multipart/form-data; boundary=" + boundary;
    esp_http_client_set_header(client_, "Content-Type", content_type.c_str());
    esp_http_client_set_header(client_, "Content-Length", std::to_string(total_len).c_str());

    // 设置POST数据
    esp_http_client_set_post_field(client_, nullptr, 0); // 准备分块传输

    // 开始请求 - 带重试机制
    const int max_retries = 5;
    const int retry_delay_ms = 1000;
    esp_err_t err = ESP_FAIL;
    
    // 打开连接重试
    for (int retry = 0; retry < max_retries; retry++) {
        err = esp_http_client_open(client_, total_len);
        if (err == ESP_OK) break;
        
        ESP_LOGW(TAG, "打开HTTP连接失败(尝试 %d/%d): %s", 
                retry + 1, max_retries, esp_err_to_name(err));
                
        if (retry < max_retries - 1) {
            esp_http_client_cleanup(client_);
            client_ = nullptr;
            vTaskDelay(pdMS_TO_TICKS(retry_delay_ms));
            
            // 重新初始化
            client_ = esp_http_client_init(&config);
            if (!client_) {
                ESP_LOGE(TAG, "HTTP客户端重新初始化失败");
                return ESP_FAIL;
            }
            
            // 重新设置参数
            esp_http_client_set_method(client_, HTTP_METHOD_POST);
            esp_http_client_set_header(client_, "Content-Type", content_type.c_str());
            esp_http_client_set_header(client_, "Content-Length", std::to_string(total_len).c_str());
            esp_http_client_set_post_field(client_, nullptr, 0);
        }
    }
    
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "打开HTTP连接失败，已达到最大重试次数");
        esp_http_client_cleanup(client_);
        client_ = nullptr;
        return err;
    }

    // 发送form-data头部 - 带重试
    for (int retry = 0; retry < max_retries; retry++) {
        int written = esp_http_client_write(client_, body.c_str(), body.length());
        if (written == body.length()) break;
        
        ESP_LOGW(TAG, "写入表单数据失败(尝试 %d/%d): 已写入 %d/%zu 字节", 
                retry + 1, max_retries, written, body.length());
                
        if (retry < max_retries - 1) {
            vTaskDelay(pdMS_TO_TICKS(retry_delay_ms));
        }
    }

    // 发送音频数据 - 带重试
    for (int retry = 0; retry < max_retries; retry++) {
        int written = esp_http_client_write(client_, (const char*)data, len);
        if (written == len) break;
        
        ESP_LOGW(TAG, "写入音频数据失败(尝试 %d/%d): 已写入 %d/%zu 字节", 
                retry + 1, max_retries, written, len);
                
        if (retry < max_retries - 1) {
            vTaskDelay(pdMS_TO_TICKS(retry_delay_ms));
        }
    }

    // 发送结束边界 - 带重试
    std::string end_boundary = "\r\n--" + boundary + "--\r\n";
    for (int retry = 0; retry < max_retries; retry++) {
        int written = esp_http_client_write(client_, end_boundary.c_str(), end_boundary.length());
        if (written == end_boundary.length()) break;
        
        ESP_LOGW(TAG, "写入结束边界失败(尝试 %d/%d): 已写入 %d/%zu 字节", 
                retry + 1, max_retries, written, end_boundary.length());
                
        if (retry < max_retries - 1) {
            vTaskDelay(pdMS_TO_TICKS(retry_delay_ms));
        }
    }

    // 完成请求 - 带重试
    for (int retry = 0; retry < max_retries; retry++) {
        err = esp_http_client_perform(client_);
        if (err == ESP_OK) break;
        
        ESP_LOGW(TAG, "HTTP请求失败(尝试 %d/%d): %s", 
                retry + 1, max_retries, esp_err_to_name(err));
                
        if (retry < max_retries - 1) {
            esp_http_client_cleanup(client_);
            client_ = nullptr;
            vTaskDelay(pdMS_TO_TICKS(retry_delay_ms));
            
            // 完全重新初始化
            client_ = esp_http_client_init(&config);
            if (!client_) {
                ESP_LOGE(TAG, "HTTP客户端重新初始化失败");
                return ESP_FAIL;
            }
            
            // 重新设置所有参数
            esp_http_client_set_method(client_, HTTP_METHOD_POST);
            esp_http_client_set_header(client_, "Content-Type", content_type.c_str());
            esp_http_client_set_header(client_, "Content-Length", std::to_string(total_len).c_str());
            esp_http_client_set_post_field(client_, nullptr, 0);
            
            // 重新打开连接
            esp_err_t open_err = esp_http_client_open(client_, total_len);
            if (open_err != ESP_OK) {
                ESP_LOGE(TAG, "重新打开HTTP连接失败: %s", esp_err_to_name(open_err));
                esp_http_client_cleanup(client_);
                client_ = nullptr;
                return open_err;
            }
            
            // 重新写入所有数据
            esp_http_client_write(client_, body.c_str(), body.length());
            esp_http_client_write(client_, (const char*)data, len);
            esp_http_client_write(client_, end_boundary.c_str(), end_boundary.length());
        }
    }
    
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "HTTP请求失败，已达到最大重试次数");
        esp_http_client_cleanup(client_);
        client_ = nullptr;
        return err;
    }

    int status_code = esp_http_client_get_status_code(client_);
    ESP_LOGI(TAG, "HTTP状态码: %d", status_code);

    esp_http_client_cleanup(client_);
    client_ = nullptr;

    return ESP_OK;
}

esp_err_t HttpsClient::postJson(const std::string& path, const std::string& json_data, int timeout_ms) {
    if (client_ != nullptr) {
        ESP_LOGW(TAG, "HTTP客户端已存在");
        return ESP_FAIL;
    }

    std::string url = base_url_ + path;
    ESP_LOGI(TAG, "🌐 正在发送JSON POST请求到: %s", url.c_str());

    esp_http_client_config_t config = {};
    config.url = url.c_str();
    config.event_handler = http_event_handler;
    config.user_data = this;
    config.timeout_ms = timeout_ms;
    config.crt_bundle_attach = esp_crt_bundle_attach;
    config.buffer_size = BUFFER_SIZE;
    config.buffer_size_tx = BUFFER_SIZE;

    client_ = esp_http_client_init(&config);
    if (client_ == nullptr) {
        ESP_LOGE(TAG, "❌ HTTP客户端初始化失败");
        return ESP_FAIL;
    }

    // 设置POST方法和内容类型
    esp_http_client_set_method(client_, HTTP_METHOD_POST);
    esp_http_client_set_header(client_, "Content-Type", "application/json");

    // 设置POST数据
    esp_http_client_set_post_field(client_, json_data.c_str(), json_data.length());

    esp_err_t err = esp_http_client_perform(client_);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "HTTP请求失败: %s", esp_err_to_name(err));
        esp_http_client_cleanup(client_);
        client_ = nullptr;
        return err;
    }

    int status_code = esp_http_client_get_status_code(client_);
    ESP_LOGI(TAG, "HTTP状态码: %d", status_code);

    esp_http_client_cleanup(client_);
    client_ = nullptr;

    return ESP_OK;
}

esp_err_t HttpsClient::postBinary(const std::string& path, const uint8_t* data, size_t len, int timeout_ms) {
    if (client_ != nullptr) {
        ESP_LOGW(TAG, "HTTP客户端已存在");
        return ESP_FAIL;
    }

    std::string url = base_url_ + path;
    ESP_LOGI(TAG, "🌐 正在发送二进制POST请求到: %s", url.c_str());

    esp_http_client_config_t config = {};
    config.url = url.c_str();
    config.event_handler = http_event_handler;
    config.user_data = this;
    config.timeout_ms = timeout_ms;
    config.crt_bundle_attach = esp_crt_bundle_attach;
    config.buffer_size = BUFFER_SIZE;
    config.buffer_size_tx = BUFFER_SIZE;

    client_ = esp_http_client_init(&config);
    if (client_ == nullptr) {
        ESP_LOGE(TAG, "❌ HTTP客户端初始化失败");
        return ESP_FAIL;
    }

    // 设置POST方法和内容类型
    esp_http_client_set_method(client_, HTTP_METHOD_POST);
    esp_http_client_set_header(client_, "Content-Type", "application/octet-stream");

    // 设置POST数据
    esp_http_client_set_post_field(client_, (const char*)data, len);

    esp_err_t err = esp_http_client_perform(client_);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "HTTP请求失败: %s", esp_err_to_name(err));
        esp_http_client_cleanup(client_);
        client_ = nullptr;
        return err;
    }

    int status_code = esp_http_client_get_status_code(client_);
    ESP_LOGI(TAG, "HTTP状态码: %d", status_code);

    esp_http_client_cleanup(client_);
    client_ = nullptr;

    return ESP_OK;
}
